/**
  ******************************************************************************
  * @file    main.c
  * @author  MCU Application Team
  * @brief   Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2023 Puya Semiconductor Co.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by Puya under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2016 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */

/*
任务：
1. 正反转.
2. 扭矩调节：3挡（0.5N.m/1N.m/2N.m), OFF档
3. 4N.m扭力
4. 选择档位，按下工作键，照明灯亮起，机器工作；松开刹停
5. 选配2000mAh电池包（4V）或4000mAh电池包（4V）
6.LED灯延时熄灭
（松开按键，机器进入休眠状态，照明灯光10S后自动关闭）
7.电池包可拆卸更换，可用作移动电源

1. 灯板PCB：有一个电位器和3个LED白 灯。当电位器转一定角度后，需要对应不同的输出速度，总共3档。LED起照明作用，当电压大于或等于2.6V时，灯照正常。当电压小于2.6V时，白灯闪烁提示，1次/S,10S后断电。灯板从主板PCBA连接电源及信号
2. 电源转接板：连接PACK电源到主板，装有3针插座（针与花瓶端子配合接触）
3. 按键PCB：上面两个按键，一个按键按住后会顺时针转，另一个按住后会逆时针转。按住才能接通，松开则电批停止，灯在松开后10S关灯
4. 主板PCBA：管控以上3板功能，获取电源电压信息
5. 当螺丝批由于扭矩太大扭不动时，需要发出报警信号，信号白灯闪烁，1次/S,闪2S停2S，按键松开则停止。

//	开发板脚位置
KEY0     	PA3					
KEY1     	PA0

//LED0			PA1
LED1			PA4 
//LED2			PA5

PWM_CH1		PA5
PWM_CH2		PA1

CTRL_A		PB2
CTRL_B		PA2

SWD				PB6
SWC				PA2

//	V1.0版本
UTX ------------ PB4（调试口）

LED_CTRL ------- PA6（LED灯控制）
KEY0 ----------- PB5（按键1）
KEY1 ----------- PB3（按键2）

AD_CURRENT ----- PB1（电流值CH0,CM1P/CM1N）
AD_SPEED ------- PA7（速度档位设置-电位器 CH4）
COMP_CURRENT --- PB0（电流保护比较器）

CTRLA ---------- PA0（A端上管开关控制，0开1关,TIM_CH1）	 PWMA
CTRLB ---------- PA3（B端上管开关控制，0开1关,TIM_CH2）	 PWMB
PWMB ----------- PA4（B端下管PWM控制）TIM1_CH3/TIM14_CH1 CTRLB
PWMA ----------- PA5（A端下管PWM控制）TIM1_CH1/TIM14_CH1 CTRLA

程序测试反馈：
									1、按键 转向方向 头掉下
                  2、照明，松开10秒后关灯，延时
                  3、要限流 
                  4、3P插针短
									限流：
									15A -3A	5000±500ms  (对应2mΩ => 0.03V 	-0.006V * 56倍 = 1.68V -0.36V)
									18A -3A	1500±200ms	(对应2mΩ => 0.036V 	-0.006V * 56倍 = 2.016V -0.36V)
									20A -3A	300±100ms		(对应2mΩ => 0.04V 	-0.006V * 56倍 = 2.24V -0.36V)
									25A -3A	100±50ms		(对应2mΩ => 0.05V 	-0.006V * 56倍 = 2.80V -0.36V)
------------------------------------------------------------------------------

//	V1.1版本
UTX ------------ PB4（调试口）

LED_CTRL ------- 改PC1（LED灯控制）
KEY0 ----------- PB5（按键1）
KEY1 ----------- PB3（按键2）

AD_CURRENT ----- PB1（电流值CM1P/CM1N  ADC_IN0）
AD_SPEED ------- PA7（速度档位设置-电位器 ADC_IN4）
AD_MID---------- PA6（电池NTC温度保护 ADC_IN3）

COMP_CURRENT --- PB0（电流保护比较器）

//	PWM
CTRLA ---------- PA0（A端上管PWM控制，0开1关,TIM_CH1）	 	PWMA
CTRLB ---------- PA3（B端上管PWM控制，0开1关,TIM_CH2）	 	PWMB

//	GPIO_OUT
PWMA ----------- PA5（A端下管开关控制，1开0关） 					CTRLA
PWMB ----------- PA4（B端下管开关控制，1开0关）						CTRLB
*/

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "py32f002bxx_ll_Start_Kit.h"

#include "userTime.h"
#include "userLed.h"
#include "userButton.h"
#include "userAdc.h"
#include "userPwm.h"
#include "userComp.h"
#include "userApplication.h"

/* Private define ------------------------------------------------------------*/
#define COUNTOF(__BUFFER__)   (sizeof(__BUFFER__) / sizeof(*(__BUFFER__)))
#define TXSTARTMESSAGESIZE    (COUNTOF(aTxStartMessage) - 1)
#define TXENDMESSAGESIZE      (COUNTOF(aTxEndMessage) - 1)

/* Private variables ---------------------------------------------------------*/
extern uint16_t systickCnt;
/* Private user code ---------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
static void APP_SystemClockConfig(void);
void APP_ConfigUsart(USART_TypeDef *USARTx);

uint32_t                      adc_value;
uint32_t                      Channel_Value;

// 以STM32F4为例（32位读取）
volatile uint32_t uid[3];

uint8_t my_FLASH_Unlock(void)
{
  uint8_t status = 0;

  if (READ_BIT(FLASH->CR, FLASH_CR_LOCK) != 0x00U)
  {
    /* Authorize the FLASH Registers access */
    WRITE_REG(FLASH->KEYR, FLASH_KEY1);
    WRITE_REG(FLASH->KEYR, FLASH_KEY2);

    /* verify Flash is unlock */
    if (READ_BIT(FLASH->CR, FLASH_CR_LOCK) != 0x00U)
    {
      status = 1;
    }
  }
	return status;
}

uint8_t my_FLASH_Lock(void)
{
  uint8_t status = 0;

  /* Set the LOCK Bit to lock the FLASH Registers access */
  SET_BIT(FLASH->CR, FLASH_CR_LOCK);

  /* verify Flash is locked */
  if (READ_BIT(FLASH->CR, FLASH_CR_LOCK) != 0x00u)
  {
    status = 1;
  }

  return status;
}

uint8_t my_OB_Unlock(void)
{
  uint8_t status = 0;

  if (READ_BIT(FLASH->CR, FLASH_CR_OPTLOCK) != 0x00U)
  {
    /* Authorizes the Option Byte register programming */
    WRITE_REG(FLASH->OPTKEYR, FLASH_OPTKEY1);
    WRITE_REG(FLASH->OPTKEYR, FLASH_OPTKEY2);

    /* verify option bytes are unlocked */
    if (READ_BIT(FLASH->CR, FLASH_CR_OPTLOCK) == 0x00U)
    {
      status = 1;
    }
  }

  return status;
}

uint8_t my_OB_Lock(void)
{
  uint8_t status = 0;

  /* Set the OPTLOCK Bit to lock the FLASH Option Byte Registers access */
  SET_BIT(FLASH->CR, FLASH_CR_OPTLOCK);

  /* verify option bytes are locked */
  if (READ_BIT(FLASH->CR, FLASH_CR_OPTLOCK) != 0x00u)
  {
    status = 1;
  }

  return status;
}

uint8_t my_OB_Launch(void)
{
  /* Set the bit to force the option byte reloading */
  SET_BIT(FLASH->CR, FLASH_CR_OBL_LAUNCH);

  /* We should not reach here : Option byte launch generates Option byte reset
     so return error */
  return 0;
}

/**
  * @brief  Set User configuration
  * @param  UserType  The FLASH User Option Bytes to be modified.
  *         This parameter can be a combination of @ref FLASH_OB_USER_Type
  * @param  UserConfig  The FLASH User Option Bytes values.
  *         This parameter can be a combination of:
  *           @arg @ref FLASH_OB_USER_BOR_ENABLE
  *           @arg @ref FLASH_OB_USER_BOR_LEVEL
  *           @arg @ref FLASH_OB_USER_IWDG_STOP
  *           @arg @ref FLASH_OB_USER_IWDG_SW
  *           @arg @ref FLASH_OB_USER_SWD_NRST
  * @retval None
  */
static void my_OB_OptrConfig(uint32_t UserType, uint32_t UserConfig)
{
  uint32_t optr;

  /* Check the parameters */
//  assert_param(IS_OB_USER_TYPE(UserType));
//  assert_param(IS_OB_USER_CONFIG(UserType, UserConfig));

  optr = FLASH->OPTR;

  optr &= ~(UserType | 0xff);
  FLASH->OPTR = (optr | UserConfig | 0xAA);
}

// 示例伪代码（需验证PY32寄存器地址）
void Enable_ReadProtection(void) {
//    FLASH_Unlock();  // 解锁Flash控制寄存器
//    FLASH_OB_Unlock(); // 解锁选项字节
//    FLASH_OB_RDP_Config(OB_RDP_LEVEL_1); // 设置Level 1保护
//    FLASH_OB_Launch(); // 重新加载选项字节
}

/**
  * @brief  Configure IWDG
  * @param  None
  * @retval None
  */
void APP_IwdgConfig(void)
{
  /* Set LSI trimming value */
  /* LL_RCC_LSI_SetCalibTrimming(LL_RCC_LSICALIBRATION_32768Hz); */
  /* Enable LSI */
  LL_RCC_LSI_Enable();
  while (LL_RCC_LSI_IsReady() == 0U) {;}

  /* Enable IWDG */
  LL_IWDG_Enable(IWDG);

  /* Enable write access to IWDG_PR, IWDG_RLR registers */
  LL_IWDG_EnableWriteAccess(IWDG);

  /* Set IWDG prescaler */
  LL_IWDG_SetPrescaler(IWDG, LL_IWDG_PRESCALER_32); 

  /* Set IWDG reload value */
  LL_IWDG_SetReloadCounter(IWDG, 1024); /* T*1024=1s */

  /* Check if all flags Prescaler, Reload & Window Value Update are reset or not */
  while (LL_IWDG_IsReady(IWDG) == 0U) {;}

  /* Reloads IWDG counter with value defined in the reload register */
  LL_IWDG_ReloadCounter(IWDG);
}

/**
  * @brief  Main program.
  * @param  None
  * @retval int
  */
int main(void)
{
  /* Configure Systemclock */
  APP_SystemClockConfig();
  /* Configure LED */
//  BSP_LED_Init(LED_WHITE);
  /* Configure USART */
  APP_ConfigUsart(USART1);
  /* Systick 时基配置为1ms */
	Systick_Init(1000);

	userButtonInit();
	userLedInit();

	userAdcInit();
	userAdcCalibrate();
	userAdcEnable();

	userCompInit();
	
	userPwmGPIOInit();
	userPWMInit();
	
	//	
	uid[0] = *((volatile uint32_t*)0x1FFF0000); // 低32位
	uid[1] = *((volatile uint32_t*)0x1FFF0004); // 中32位
	uid[2] = *((volatile uint32_t*)0x1FFF0008); // 高32位
	printf("\r\nUID[0]:0x%04x,UID[1]:0x%04x,UID[2]:0x%04x",uid[0],uid[1],uid[2]);
  /* Infinite loop */
  while (1)
  {
		userButtonProcess();
		userLedProcess();
		userAdcProcess();
//		userCompProcess();
		
//		if((uid[0] == 0x4150344c)&&(uid[1] == 0x37373808)&&(uid[2] == 0x453744))
		{
			userAppProcess();
		}
		
		/* Reloads IWDG counter with value defined in the reload register */
    LL_IWDG_ReloadCounter(IWDG);
  }
}
 
/**
  * @brief  Configure Systemclock
  * @param  None
  * @retval None
  */
static void APP_SystemClockConfig(void)
{
  /* Enable HSI */
  LL_RCC_HSI_Enable();
  while(LL_RCC_HSI_IsReady() != 1)
  {
  }

  /* Set AHB divider: HCLK = SYSCLK */
  LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);

  /* HSISYS used as SYSCLK clock source  */
  LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSISYS);
  while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSISYS)
  {
  }

  /* Set APB1 divider */
  LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1);
  LL_Init1msTick(24000000);

  /* Update CMSIS variable (which can be updated also through SystemCoreClockUpdate function) */
  LL_SetSystemCoreClock(24000000);
}

/**
  * @brief  USART configuration functions
  * @param  USARTx：USART1 Instance
  * @retval None
  */
void APP_ConfigUsart(USART_TypeDef *USARTx)
{
  /* Enable clock, initialize GPIO, enable NVIC interrupt */
  if (USARTx == USART1)
  {
    /* Enable GPIOB clock */
    LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOB);
    /* Enable USART1 peripheral clock */
    LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_USART1);

    /* Initialize PB4 */
    LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
    /* Select pin 4 */
    GPIO_InitStruct.Pin = LL_GPIO_PIN_4;
    /* Select alternate mode */
    GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
    /* Set output speed */
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
    /* Set output type to push pull */
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    /* Enable pull up */
    GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
    /* Set alternate function to USART1 function  */
    GPIO_InitStruct.Alternate = LL_GPIO_AF1_USART1;
    /* Initialize GPIOB */
    LL_GPIO_Init(GPIOB,&GPIO_InitStruct);

//	关闭串口接收脚
//    /* Select pin 5 */
//    GPIO_InitStruct.Pin = LL_GPIO_PIN_5;
//    /* Set alternate function to USART1 function */
//    GPIO_InitStruct.Alternate = LL_GPIO_AF1_USART1;
    /* Initialize GPIOB */
    LL_GPIO_Init(GPIOB,&GPIO_InitStruct);
  }

  /* Set USART feature */
  LL_USART_InitTypeDef USART_InitStruct = {0};
  /* Set baud rate */
  USART_InitStruct.BaudRate = 115200;
  /* set word length to 8 bits: Start bit, 8 data bits, n stop bits */
  USART_InitStruct.DataWidth = LL_USART_DATAWIDTH_8B;
  /* 1 stop bit */
  USART_InitStruct.StopBits = LL_USART_STOPBITS_1;
  /* Parity control disabled  */
  USART_InitStruct.Parity = LL_USART_PARITY_NONE;
  USART_InitStruct.TransferDirection = LL_USART_DIRECTION_TX;		//LL_USART_DIRECTION_TX_RX;
  USART_InitStruct.HardwareFlowControl = LL_USART_HWCONTROL_NONE;
  USART_InitStruct.OverSampling = LL_USART_OVERSAMPLING_16;
  /* Initialize USART */
  LL_USART_Init(USARTx, &USART_InitStruct);

  /* Configure as full duplex asynchronous mode */
  LL_USART_ConfigAsyncMode(USARTx);

  /* Enable USART */
  LL_USART_Enable(USARTx);
}

/**
  * @brief  Error handling function
  * @param  None
  * @retval None
  */
void APP_ErrorHandler(void)
{
  /* Infinite loop */
  while (1)
  {
  }
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file：Pointer to the source file name
  * @param  line：assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* User can add His own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* Infinite loop */
  while (1)
  {
  }
}
#endif /* USE_FULL_ASSERT */

/************************ (C) COPYRIGHT Puya *****END OF FILE******************/
